package com.wu.shiro;

import com.wu.common.CommonConst;
import com.wu.entity.ShiroUser;
import com.wu.service.impl.UserService;
import com.wu.util.EncryptUtil;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;

import java.util.HashSet;
import java.util.Set;

/**
 * @author wuyanshen
 * @date 2019-01-13 11:57 AM
 * @discription 描述
 */
public class MyRealm extends AuthorizingRealm {

    private static final Logger logger = LoggerFactory.getLogger(MyRealm.class);

    @Autowired
    @Lazy
    private UserService userService;

    /**
     * 大坑！，必须重写此方法，不然Shiro会报错
     */
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        logger.info("第一个Realm token是:" + authenticationToken);
        logger.info(" doGetAuthenticationInfo token hash->" + authenticationToken.hashCode());

        //1.将AuthenticationToken转化成UserNamePasswordToken
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;

        //2.UserNamePasswordToken中获取loginName
        String loginName = usernamePasswordToken.getUsername();

        //3.调用数据库获取loginName对应的记录
        logger.info("从数据库取出用户信息");
        ShiroUser shiroUser = userService.getUserByLoginName(loginName);

        //4.若记录不存在,则抛出AuthenticationException
        if (shiroUser==null) {
            logger.info("数据库不存在用户信息");
            throw new UnknownAccountException("用户不存在");
        }

        if (CommonConst.IS_LOCK.equals(shiroUser.getIsLocked())) {
            logger.info("账户已被锁定");
            throw new LockedAccountException("账户已被锁定");
        }

        //将页面提交过来的密码进行md5加密
        String credentials = EncryptUtil.encrypt(loginName, String.valueOf(usernamePasswordToken.getPassword()), "MD5");

//        if (!credentials.equals(shiroUser.getPassword())) {
//            throw new IncorrectCredentialsException("用户密码错误");
//        }

        //5.根据用户的情况,来构建AuthenticationInfo 对象返回
        //第一个参数principal:认证的实体信息,可以是userName,也可以是用户的实体对象
        //第二个参数credentials:密码
        //1):将密码md5加密
        //2):替换默认的密码比对器CredentialsMatcher为其他密码匹配器,如HashedCredentialsMatcher
        //3):加入盐,盐值需要唯一,使每个密码对应的md5值都不一样
        ByteSource salt = ByteSource.Util.bytes(loginName);

        //第三个参数realmName:当前realm对象的name,调用父类的getName()方法即可
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(loginName, shiroUser.getPassword(), salt, getName());

        return info;
    }


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("第一个Realm 准备授权...");

        //1.从PrincipalCollection中获取登录信息
        Object principal = principalCollection.getPrimaryPrincipal();

        //2.利用登录信息获取用户的角色或者权限信息
        Set<String> roles = new HashSet<>();
        roles.add("USER");
        if ("admin".equals(principal)) {
            roles.add("ADMIN");
        }

        //3.创建 SimpleAuthorizationInfo ,并设置Roles属性
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roles);

        //4.返回SimpleAuthorizationInfo
        return info;
    }

    public static void main(String[] args) {
        Object credit = "123";
        ByteSource salt = ByteSource.Util.bytes("admin");
        Object result = new SimpleHash("MD5", credit, salt, 1024);

        String username = "admin";
        String passoword = "123";
        result = EncryptUtil.encrypt(username,passoword,"MD5");
        System.out.println(result);
    }

}
